﻿//************************************************************************************************************
// CoNatural.Data.dll
// Author: Roger Torres
//************************************************************************************************************
// You can use, modify, and distribute the source code and executable programs based on the source code.
// This source code is provided "as is" and without warranties as to performance or merchantability. 
// The author and/or distributors of this source code may have made statements about this source code. 
// Any such statements do not constitute warranties and shall not be relied on by the user in deciding 
// whether to use this source code. This source code is provided without any express or implied warranties 
// whatsoever. Because of the diversity of conditions and hardware under which this source code may be used, 
// no warranty of fitness for a particular purpose is offered. The user is advised to test the source code 
// thoroughly before relying on it. The user must assume the entire risk of using the source code.
//************************************************************************************************************

using System;
using System.Collections.Generic;
using System.Data;
using CoNatural.Data.Binders;
#if !NET40
using CoNatural.Helpers;
#endif

namespace CoNatural.Data {
	/// <summary>
	/// A delegate invoked by generic readers to materialize data records into T
	/// </summary>
	/// <typeparam name="T">The type we are materializing.</typeparam>
	/// <param name="context">The reader execution context.</param>
	/// <returns>The target instance.</returns>
	public delegate T ReaderCallback<T>(ReaderExecutionContext<T> context) where T : class, new();

	/// <summary>
	/// EventArgs passed on command execution events
	/// </summary>
	public class CommandExecutionEventArgs : EventArgs {
		/// <summary>
		/// The command execution context
		/// </summary>
		public IExecutionContext Context { get; private set; }

		/// <summary>
		/// Flag to ignore exceptions and continue
		/// </summary>
		public bool IgnoreErrors { get; set; }

		internal CommandExecutionEventArgs(IExecutionContext context) {
			Context = context;
			IgnoreErrors = false;
		}
	}

	public interface IConnection {
		#region Properties

		/// <summary>
		/// Gets the data binder associated to this connection.
		/// </summary>
		IDataBinder DataBinder { get; }

		/// <summary>
		/// Gets the connection string associated to this connection.
		/// </summary>
		string ConnectionString { get; }

		/// <summary>
		/// Gets or sets the timeout to be used when executing commands.
		/// </summary>
		int TimeOut { get; set; }

		/// <summary>
		/// Gets or sets the current execution mode of commands.
		/// </summary>
		CommandType ExecutionMode { get; set; }

		#endregion

		#region Command Execution

		/// <summary>
		/// Invoked by the framework before executing commands.
		/// </summary>
		event EventHandler<CommandExecutionEventArgs> BeforeExecute;

		/// <summary>
		/// Invoked by the framework after executing commands. 
		/// </summary>
		event EventHandler<CommandExecutionEventArgs> AfterExecute;

		/// <summary>
		/// Executes command invoking ADO.NET Command.ExecuteNonQuery internally.
		/// Output parameters can be used to pass results back to command.
		/// </summary>
		/// <param name="iCommand">The command.</param>
		/// <returns>The number of records affected.</returns>
		int Execute(ICommand iCommand);

		/// <summary>
		/// Executes command invoking ADO.NET Command.ExecuteScalar internally.
		/// Output parameters can be used to pass results back to command.
		/// </summary>
		/// <typeparam name="T">The first column of the first row in the resultset as T. Extra columns or rows are ignored.</typeparam>
		/// <param name="iCommand">The command.</param>
		/// <returns>The instance of T.</returns>
		T ExecuteScalar<T>(ICommand iCommand);

		/// <summary>
		/// Executes command as data reader, materializing the first record into an instance of T using the default type materializer. 
		/// </summary>
		/// <typeparam name="T">The type we are materializing.</typeparam>
		/// <param name="iCommand">The command.</param>
		/// <returns>An instance of the first record as T.</returns>
		T Execute<T>(ICommand iCommand) where T : class, new();

		/// <summary>
		/// Executes command as data reader, materializing the first record into an instance of T. 
		/// </summary>
		/// <typeparam name="T">The type we are materializing.</typeparam>
		/// <param name="iCommand">The command.</param>
		/// <param name="callback">The callback delegate that materializes data records into instances of T.</param>
		/// <returns>An instance of the first record as T.</returns>
		T Execute<T>(ICommand iCommand, ReaderCallback<T> callback) where T : class, new();

		/// <summary>
		/// Executes command as data reader, materializing all records into a list of instances of T using default type materializer.
		/// </summary>
		/// <typeparam name="T">The type we are materializing.</typeparam>
		/// <param name="iCommand">The command.</param>
		/// <returns>An enumerable list of T.</returns>
		IEnumerable<T> ExecuteReader<T>(ICommand iCommand) where T : class, new();

		/// <summary>
		/// Executes command as data reader, materializing all records into a list of instances of T.
		/// </summary>
		/// <typeparam name="T">The type we are materializing.</typeparam>
		/// <param name="iCommand">The command.</param>
		/// <param name="callback">The callback delegate that materializes data records into instances of T.</param>
		/// <returns>An enumerable list of T.</returns>
		IEnumerable<T> ExecuteReader<T>(ICommand iCommand, ReaderCallback<T> callback) where T : class, new();

		/// <summary>
		/// Executes command as data reader, materializing all records inside a target object. 
		/// </summary>
		/// <typeparam name="T">The target type.</typeparam>
		/// <param name="iCommand">The command implementing IReader of T.</param>
		/// <param name="target">The target object.</param>
		/// <returns>The number of materialized records.</returns>
		int ExecuteReader<T>(T target, ICommand iCommand) where T : class, new();

		/// <summary>
		/// Executes command as data reader, materializing all records inside a target object. 
		/// </summary>
		/// <typeparam name="T">The target type.</typeparam>
		/// <param name="iCommand">The command.</param>
		/// <param name="target">The target object.</param>
		/// <param name="callback">The callback delegate that materializes data records inside the target object.</param>
		/// <returns>The number of materialized records.</returns>
		int ExecuteReader<T>(T target, ICommand iCommand, ReaderCallback<T> callback) where T : class, new();

		/// <summary>
		/// Executes command bound to an object.
		/// </summary>
		/// <param name="iCommand">The command.</param>
		/// <param name="obj">The object.</param>
		/// <returns>The number of rows affected.</returns>
		int Execute(ICommand iCommand, object obj);

		/// <summary>
		/// Executes a list of commands in order.
		/// </summary>
		/// <param name="iCommands">The list of commands.</param>
		void Execute(params ICommand[] iCommands);

		/// <summary>
		/// Executes command bound to a list of objects.
		/// </summary>
		/// <param name="iCommand">The command.</param>
		/// <param name="objs">The list of objects.</param>
		/// <param name="inBatch">Execute all commands in a single batch. (StoredProcedure execution mode only).</param>
		void Execute(ICommand iCommand, IEnumerable<object> objs, bool inBatch);

		/// <summary>
		/// Executes a list of commands in order.
		/// </summary>
		/// <param name="iCommands">The list of commands.</param>
		/// <param name="inBatch">Execute all commands in a single batch. (StoredProcedure execution mode only).</param>
		void Execute(IEnumerable<ICommand> iCommands, bool inBatch);

		/// <summary>
		/// Binds commands to objects and executes them in order.
		/// </summary>
		/// <typeparam name="T">The type of input objects.</typeparam>
		/// <param name="objs">The list of input objects.</param>
		/// <param name="tupleBinder">The function that binds commands to output objects.</param>
		/// <param name="inBatch">Execute all commands in a single batch. (StoredProcedure execution mode only).</param>
		void Execute<T>(IEnumerable<T> objs, Func<T, Tuple<object, ICommand>> tupleBinder, bool inBatch);

		#endregion
	}
}
